﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace Diplomova_prace
{

    class Aproximation_alg
    {

        Polynoms p;
        public Tuple<List<SeznamNtic>,List<SeznamNtic>,List<SeznamNtic>,SeznamNtic,ntice> LagrangeuvPolynom(List<double> X, List<double> Y)
        {
            
            List<SeznamNtic> listjmen = new List<SeznamNtic>();
            SeznamNtic listnas = new SeznamNtic();
            List<SeznamNtic> jednopol = new List<SeznamNtic>();
            List<SeznamNtic> jednopolSoucin = new List<SeznamNtic>();
            ntice vysl = new ntice(true);
            if (X.Count != Y.Count)
                throw new Exception("Počet bodů se nerovná počtu funkčních hodnot");
            List<List<double>> subPolynomy = new List<List<double>>();
            SeznamNtic poly = new SeznamNtic();
            SeznamNtic subpol = new SeznamNtic();
            for (int i = 0; i < X.Count; i++)
            { // priprava polynomu (x-xi)
                subpol.Add(new ntice(new List<double>(){(-1) * X[i], 1},true));
            }
            for (int i = 0; i < X.Count; i++)
            {
                SeznamNtic funpol = new SeznamNtic();
                SeznamNtic temp = new SeznamNtic();
                SeznamNtic structtemp = new SeznamNtic();
                SeznamNtic tmpSoucinPol = new SeznamNtic();
                double jmenovatel = 1;
                for (int j = 0; j < X.Count; j++)
                { //priprava konkretniho citatele ( jednotlive polynomy) a konkretniho jmenovatele
                    if (j == i)
                        continue;
                    else
                    {
                        jmenovatel *= X[i] - X[j];
                        temp.Add(new ntice(new List<double>(){X[i], -X[j]}, false));
                        funpol.Add(subpol.list[j]);      
                    }
                }
                listjmen.Add(temp);
             
                structtemp.Copy(funpol.list);
                jednopol.Add(structtemp);
                for (int k = funpol.list.Count - 1; k > 0; k--)
                { // vynasobeni citatele (jednotlivych polynomu)
                    p = new Polynoms();
                    List<double> mulpol = new List<double>(p.Nasobeni(funpol.list[k].hodnoty, funpol.list[k-1].hodnoty));
                    funpol.RemoveAtList(k);
                    funpol.RemoveAtList(k - 1);
                    funpol.Add(new ntice(mulpol,true));

                }
                tmpSoucinPol.Copy(funpol.list);
                jednopolSoucin.Add(tmpSoucinPol);
                //vypocteni polynomu a pridani do Polynomy
                List<double> jmenovatele = new List<double>() { 1 / jmenovatel };
                p = new Polynoms();
                List<double> nasobek = new List<double>() { Y[i] };

                ntice jmen = new ntice(new List<double>() { 1 / jmenovatel }, false);
                ntice nas = new ntice(new List<double>() { Y[i] }, false);
                
                funpol.list[0] = new ntice(new List<double>(p.Nasobeni(funpol.list[0].hodnoty, jmen.hodnoty)), false);
                listnas.Add(nas);
                funpol.list[0] = new ntice(new List<double>(p.Nasobeni(funpol.list[0].hodnoty, nas.hodnoty)), false);
                poly.Add(funpol.list[0]);
            }
            for (int i = poly.list.Count - 1; i > 0; i--)
            {
                //secteni polynomu v jeden vysledny polynom
                p = new Polynoms();
                List<double> add = new List<double>(p.Soucet(poly.list[i].hodnoty, poly.list[i - 1].hodnoty));
                poly.RemoveAtList(i);
                poly.RemoveAtList(i - 1);
                poly.Add(new ntice(add, true));

            }
            vysl = new ntice(poly.list[0].hodnoty, true);
                
            return Tuple.Create(jednopol, jednopolSoucin, listjmen,listnas, vysl);
        }
        public Tuple<SeznamNtic,SeznamNtic,SeznamNtic,SeznamNtic,List<double>,List<double>,ntice> NewtonuvPolynom(List<double> X, List<double> Y)
        { // List<SeznamNtic> 
            if (X.Count != Y.Count)
                throw new Exception("Počet bodů se nerovná počtu funkčních hodnot");
            List<double> koefDia = new List<double>();
            List<double> valF = new List<double>();
            List<double> prevIt = new List<double>(Y);
            SeznamNtic diffNum = new SeznamNtic();
            SeznamNtic diffDen = new SeznamNtic();
            List<double> valDiff = new List<double>();
            List<double> temp = new List<double>();
            koefDia.Add(Y[0]);
            for (int j = 0; j < Y.Count - 1; j++)
            {
                for (int i = 1; i < prevIt.Count; i++)
                {
                    valF.Add((prevIt[i] - prevIt[i - 1]) / (X[i + j] - X[i - 1]));
                    temp.Add(valF.Last());
                    diffNum.Add(new ntice(new List<double> { prevIt[i], prevIt[i - 1] }, false));
                    diffDen.Add(new ntice(new List<double> { X[i + j], X[i - 1] }, false));
                    if (i == 1)
                    {
                        koefDia.Add(valF[i - 1]);
                    }
                }
                prevIt = new List<double>(valF);
                valF = new List<double>();
            }
            valDiff = new List<double>(temp);
            //priprava polynomu
            SeznamNtic subPol = new SeznamNtic();
            SeznamNtic Pol = new SeznamNtic();
            for (int i = 0; i < X.Count; i++)
            {
                subPol.Add(new ntice(true));
                subPol.list[i].Add(-X[i]);
                subPol.list[i].Add(1);
            }
            Pol.Add(new ntice(new List<double>() { 1 }, true));
            Pol.Add(subPol.list[0]);

            p = new Polynoms();
            for (int i = 2; i < Y.Count; i++)
            {
                Pol.Add(new ntice(true));
                Pol.list[i] = new ntice(p.Nasobeni(Pol.list[i - 1].hodnoty, subPol.list[i-1].hodnoty),true);
            }
            for (int i = 0; i < Pol.list.Count; i++)
            {
                Pol.list[i] = new ntice(p.Nasobeni(new List<double>(){ koefDia[i]},Pol.list[i].hodnoty), true);  
            }
            SeznamNtic roznasobeneSubPol = new SeznamNtic();
            roznasobeneSubPol.Copy(Pol.list);
            for (int i = Pol.list.Count - 1; i > 0; i--)
            {
                List<double> add = new List<double>(p.Soucet(Pol.list[i].hodnoty, Pol.list[i - 1].hodnoty));
                Pol.RemoveAtList(i);
                Pol.RemoveAtList(i - 1);
                Pol.Add(new ntice(add, true));
            }
            ntice res = new ntice(Pol.list[0].hodnoty, true);
            return Tuple.Create(subPol, roznasobeneSubPol, diffNum, diffDen, koefDia, valDiff, res);
        }
        public Tuple<SeznamNtic, List<double>, List<double>, List<double>> KvadratickySplajn(List<double> X, List<double> Y)
        {
            p = new Polynoms();
            if (X.Count != Y.Count)
                throw new Exception("Počet bodů se nerovná počtu funkčních hodnot");
            SeznamNtic Polynomy = new SeznamNtic();
            List<double> Di = new List<double>();
            Di.Add(0); //prirozeny spline, kdyz Di[0] =0 ;Di[0] =(y2-y1)/(x2-x1) dalsi moznost - prvni polynom bude linearni (vzdy) 
            for (int i = 1; i < X.Count; i++)
            {
                Di.Add(2 * ((Y[i] - Y[i - 1]) / (X[i] - X[i - 1])) - Di[i - 1]);
            }
            for (int i = 0; i < X.Count - 1; i++)
            {
                List<double> SoucinNadruhou = p.Nasobeni(new List<double>() { -X[i], 1 }, new List<double>() { -X[i], 1 });
                List<double> LevaStrana = p.Nasobeni(new List<double>() { (Di[i + 1] - Di[i]) / (2 * (X[i + 1] - X[i])) }, SoucinNadruhou);
                List<double> Soucin = p.Nasobeni(new List<double>() { Di[i] }, new List<double>() { -X[i], 1 });
                List<double> PravaStrana = p.Soucet(Soucin, new List<double>() { Y[i] });
                List<double> Sum = p.Soucet(LevaStrana, PravaStrana);
                Polynomy.Add(new ntice(Sum, true));
            }
            return Tuple.Create(Polynomy,X,Y,Di);
        }
        public Tuple<SeznamNtic, List<double>, List<double>> LinearniSplajn(List<double> X, List<double> Y)
        {
            if (X.Count != Y.Count)
                throw new Exception("Počet bodů se nerovná počtu funkčních hodnot");
            SeznamNtic Polynomy = new SeznamNtic();
            for (int i = X.Count - 1; i > 0; i--)
            {
                double konstanta = Y[i - 1] + ((Y[i] - Y[i - 1]) / (X[i] - X[i - 1])) * (-X[i - 1]);
                double x = (Y[i] - Y[i - 1]) / (X[i] - X[i - 1]);
                Polynomy.Add(new ntice(new List<double>(){konstanta,x},true));
            }
            return Tuple.Create(Polynomy, X, Y);
        }
    }
}
